<?php

defined('BASEPATH') or die('forbidden');
/**
 * 公用辅助函数
 * @author  Karson
 * @name    common.php
 * @since   2012-8-31 14:46:07
 */

/**
 * 输出Ajax的Header信息
 */
function ajax() {
    @header("Pragma:no-cache\r\n");
    @header("Cache-Control:no-cache\r\n");
    @header("Expires:0\r\n");
}

/**
 * 数组转换为字符
 * @param array $array 数组
 * @param int $level 深度
 * @return string
 */
function array2val($array, $level = 0) {
    $space = '';
    for ($i = 0; $i <= $level; $i++) {
        $space .= "\t";
    }
    $evaluate = "array\n$space(\n";
    $comma = $space;
    foreach ($array as $key => $val) {
        $key = is_string($key) ? '\'' . $key . '\'' : $key;
        if (is_bool($val)) {
            $val = $val ? 'true' : 'false';
        } else if ($val != 'true' && $val != 'false') {
            $val = !is_array($val) && (!preg_match("/^\-?\d+$/", $val) || strlen($val) > 12) ? '\'' . $val . '\'' : $val;
        }
        if (is_array($val)) {
            $evaluate .= "$comma$key => " . array2val($val, $level + 1);
        } else {
            $evaluate .= "$comma$key => $val";
        }
        $comma = ",\n$space";
    }
    $evaluate .= "\n$space)";
    return $evaluate;
}

/**
 * 二维数组排序
 * @param array $arr 需要排序的数组 二维数组
 * @param string $keys 排序的键名
 * @param string $type 排序的顺序 SORT_ASC或SORT_DESC
 * @return array
 */
function array_sort($ArrayData, $KeyName1, $SortOrder1 = "SORT_ASC", $SortType1 = "SORT_REGULAR") {
    if (!is_array($ArrayData) || !$ArrayData) {
        return $ArrayData;
    }

    $ArgCount = func_num_args();

    for ($I = 1; $I < $ArgCount; $I++) {
        $Arg = func_get_arg($I);
        if (!preg_match("/SORT_(.*)/i", $Arg)) {
            $KeyNameList[] = $Arg;
            $SortRule[] = '$' . $Arg;
        } else {
            $SortRule[] = $Arg;
        }
    }

    foreach ($ArrayData AS $Key => $Info) {
        foreach ($KeyNameList AS $KeyName) {
            ${$KeyName}[$Key] = $Info[$KeyName];
        }
    }

    $EvalString = 'array_multisort(' . join(",", $SortRule) . ',$ArrayData);';
    eval($EvalString);
    return $ArrayData;
}

/**
 * 移除数组第一个元素并保留键名
 * @param array $arr
 * @return array
 */
function array_kshift(&$arr) {
    list($k) = array_keys($arr);
    $r = array($k => $arr[$k]);
    unset($arr[$k]);
    return $r;
}

/**
 * 一维数组相加
 * @return array
 */
function array_add() {
    $c = array();
    $argv = func_get_args();
    foreach ($argv as $m => $n) {
        foreach ($n as $k => $v) {
            if (isset($c[$k])) {
                $c[$k] = $c[$k] + $n[$k];
            } else {
                $c[$k] = $n[$k];
            }
        }
    }
    return $c;
}
function array_merge_multi() {
    // Holds all the arrays passed
    $params = func_get_args ();
    
    // First array is used as the base, everything else overwrites on it
    $return = array_shift ( $params );
    
    // Merge all arrays on the first array
    foreach ( $params as $array ) {
        foreach ( $array as $key => $value ) {
            // Numeric keyed values are added (unless already there)
            if (is_numeric ( $key ) && (! in_array ( $value, $return ))) {
                if (is_array ( $value )) {
                    $return [] = $this->array_merge_replace_recursive ( $return [$$key], $value );
                } else {
                    $return [] = $value;
                }
                
            // String keyed values are replaced
            } else {
                if (isset ( $return [$key] ) && is_array ( $value ) && is_array ( $return [$key] )) {
                    $return [$key] = array_merge_multi ( $return [$key], $value );
                } else {
                    $return [$key] = $value;
                }
            }
        }
    }
    
    return $return;
}

/**
 * 将数组键名全部改为大写
 * @param array $array
 */
function array_key_upper($array) {
    $arr = array();
    foreach ($array as $m => $n) {
        $arr[strtoupper($m)] = is_array($n) ? array_key_upper($n) : $n;
    }
    return $arr;
}

/**
 * 判断判断字符
 * @param string $str
 * @return string
 */
function checkorder($str = "asc") {
    $value = strtolower($str);
    return $value == "desc" ? "asc" : "desc";
}

/**
 * 检查是否选择
 * @param mixed $temp 临时值
 * @param mixed $value 比较值
 * @return string
 */
function checkselected($temp, $value) {
    return $temp == $value ? "selected" : '';
}

/**
 * 检查是否复选
 * @param mixed $temp 临时值
 * @param mixed $value 比较值
 * @return string
 */
function checkchecked($temp, $value) {
    return $temp == $value ? "checked" : '';
}

/**
 * 判断是否在数组中
 * @param string $data 判断的字符
 * @param array $array 判断的数组
 * @param mixed $true 为真是返回的数据
 * @param mixed $false 为假时返回的数据
 * @return mixed
 */
function checkinarray($data, $array, $true = 'checked', $false = '') {
    return isset($array) && is_array($array) && in_array($data, $array) ? $true : $false;
}

/**
 * 自定义md5加密算法
 * @param string $data 加密数据
 * @return string
 */
function md5s($data, $len = 32) {
    $data = md5($data);
    $data = strtoupper($data);
    $data = strrev($data);
    return substr(md5($data), 0, $len);
}

/**
 * 判断IP是否在黑名单里
 * @param string $userip 用户IP
 * @param array $badiplist 禁止访问的IP及IP段数组
 * @return boolean
 */
function check_ip($userip, $badiplist) {
    //$badip = explode("\n",$badiplist);
    $badip = $badiplist;
    $ippart = explode(".", $userip);
    if (!is_array($badip))
        return false;
    for ($i = 0; $i < count($badip); $i++) {
        $m = 0;
        $badippart = explode(".", $badip[$i]);
        for ($j = 0; $j < count($badippart); $j++) {
            if ((trim((string) $badippart[$j]) == "*") || (trim((string) $ippart[$j]) == trim((string) $badippart[$j]))) {
                $m++;
            }
        }
        if ($m == 4)
            return true;
    }
    return false;
}

/**
 * 判断传入的字符是否含有非法字符
 * @param string $string 判断的数据
 * @return boolean 有非法字符返回true,无返回字符返回false
 */
function check_filter_words($string = '') {
    $words = file_get_contents(BASEPATH . 'commons/filterwords.txt');
    $words = array_filter(explode("\r\n", $words));
    $words = str_replace($words, '**', $string);
    return stripos($words, "**") !== false ? true : false;
}

/**
 * 获取过滤后的字符数据
 * @param string $string 过滤的数据
 * @param string $filter 替换的字符,默认为***
 * @return string
 */
function get_filter_words($string = '', $filter = '***') {
    $words = file_get_contents(BASEPATH . 'commons/filterwords.txt');
    $words = array_filter(explode("\r\n", $words));
    return str_replace($words, $filter, $string);
}

/**
 * 中文字符截取
 * @param string $string 截取的字符数据
 * @param int $length 截取的字符长度
 * @param string $dot 截取后的字符加上的字符，默认为...
 * @param string $charset 字符编码，默认为utf-8
 * @return string 截取后的数据
 */
function cutstr($string, $length, $dot = '...', $charset = 'utf-8') {
    if (strlen($string) <= $length || $length <= 0)
        return $string;
    $string = str_replace(array('&nbsp;', '&amp;', '&quot;', '&#039;', '&ldquo;', '&rdquo;', '&mdash;', '&lt;', '&gt;', '&middot;', '&hellip;'), array(' ', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), $string);
    $strcut = '';
    if (strtolower($charset) == 'utf-8') {
        $n = $tn = $noc = 0;
        while ($n < strlen($string)) {
            $t = ord($string[$n]);
            if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                $tn = 1;
                $n++;
                $noc++;
            } else if (194 <= $t && $t <= 223) {
                $tn = 2;
                $n += 2;
                $noc += 2;
            } else if (224 <= $t && $t < 239) {
                $tn = 3;
                $n += 3;
                $noc += 2;
            } else if (240 <= $t && $t <= 247) {
                $tn = 4;
                $n += 4;
                $noc += 2;
            } else if (248 <= $t && $t <= 251) {
                $tn = 5;
                $n += 5;
                $noc += 2;
            } else if ($t == 252 || $t == 253) {
                $tn = 6;
                $n += 6;
                $noc += 2;
            } else {
                $n++;
            }
            if ($noc >= $length)
                break;
        }
        if ($noc > $length)
            $n -= $tn;
        $strcut = substr($string, 0, $n);
    } else {
        for ($i = 0; $i < $length - strlen($dot) - 1; $i++)
            $strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
    }
    $strcut = str_replace(array('&', '"', '<', '>'), array('&', '"', '&lt;', '&gt;'), $strcut);
    return $strcut . $dot;
}

/**
 * 读取游戏配置数据
 * @param string $id 配置ID
 * @param string $split 分隔符
 * @return mixed
 */
function config_value($id, $split = null) {
    $framework = get_instance('controller');
    $value = $framework->configvalue->get_configvalue($id);
    if ($value) {
        $value = json_decode($value, TRUE);
        if (!is_array($value) && !is_null($split)) {
            $value = explode($split, $value);
        }
    }
    return $value;
}

/**
 * 读取VIP配置数据
 * @param string $id 字段数据
 * @param int $vip VIP等级,默认为当前玩家的等级
 * @return mixed
 */
function vip_value($field, $vip = null) {
    $framework = get_instance('controller');
    $vip = is_null($vip) ? $framework->auth->fields['vip'] : $vip;
    $vipdata = $framework->vip->get_vip($vip);
    $value = isset($vipdata[$field]) ? $vipdata[$field] : '';
    if (in_array($value, array('true', 'false'), true)) {
        $value = $value == 'true' ? true : false;
    }
    return $value;
}

/**
 * 读取公式的计算结果
 * @param string $id 公式的ID
 * @param array $var 替换的数据
 * @param bool $debug 是否打印公式数据,只供测试使用
 * @return string
 */
function formula_value($id, $var = array(), $debug = false) {
    $framework = get_instance('controller');
    $formula = $framework->formula->get_formula($id);
    if ($formula) {
        if (!is_numeric($formula) || !$var) {
            $f = '$formula = ' . strtr($formula, $var) . ';';
            if ($debug) {
                debug($f);
            }
            try {
                eval($f);
            } catch (Exception $e) {
                
            }

            return $formula;
        }
    }
    return $formula;
}

/**
 * 正规替换(加强版str_replace)
 * @return string
 */
function stro_replace($search, $replace, $subject) {
    return strtr($subject, array_combine($search, $replace));
}

/**
 * 修改配置文件
 * @param array $config 配置数组
 */
function change_config($config) {
    $framework = get_instance('controller');
    //去除转义字符
    $config_all = $framework->input->deep_stripslashes($framework->config);
    $config_all['url_search'] = $framework->config['url_search'];
    //将重叠的配置项合并
    foreach ($config as $m => $n) {
        if (isset($config_all[$m])) {
            $config_all[$m] = is_array($config_all[$m]) ? array_merge($config_all[$m], $n) : $n;
        } else {
            $config_all = array_merge($config_all, is_array($n) ? $n : array($m => $n));
        }
    }
    $config = $framework->input->deep_addslashes($config_all);
    $config['url_search'] = $framework->input->deep_stripslashes($config['url_search']);
    unset($config['db']);
    //缓冲开始
    ob_start();
    echo "<?php \ndefined('BASEPATH') or die('forbidden');\n//配置\n\$config = ";
    echo array2val($config);
    echo ";";
    $content = ob_get_contents();
    ob_clean();
    //将合并后的值传回对象
    $framework->config = $config_all;
    //写文件
    @file_put_contents(dirname(BASEPATH) . '/application/configs/config.php', $content);
    return $config;
}

/**
 * 删除最后一个指定的字符
 * @param string $string 需要处理的字符
 * @param string $char 需要删除的字符
 * @return string
 */
function del_lastchar($string, $char = ',') {
    $string = substr($string, -1) == $char ? substr($string, 0, -1) : $string;
    return $string;
}

/**
 * 下载
 * @param string $filename 文件路径,根目录开始
 * @return bool 成功则下载文件，失败返回false
 */
function download($filename) {
    $filepath = dirname(BASEPATH) . $filename;

    $filename = basename($filepath);
    $filepath = iconv('UTF-8', 'GBK', $filepath);

    if (file_exists($filepath)) {
        $filename_encode = urlencode($filename);
        $filename_encode = str_replace("+", "%20", $filename_encode);
        //$filename_encode = str_replace("%80", "", $filename_encode);
        $ua = $_SERVER["HTTP_USER_AGENT"];

        header('Content-Type: application/octet-stream');
        if (preg_match("/MSIE|Chrome/", $ua)) {
            header('Content-Disposition: attachment; filename="' . $filename_encode . '"');
        } else if (preg_match("/Firefox/", $ua)) {
            header('Content-Disposition: attachment; filename*="utf8\'\'' . $filename . '"');
        } else {
            header('Content-Disposition: attachment; filename="' . $filename . '"');
        }
        readfile($filepath);
        exit;
    }
    return false;
}

/**
 * 格式化文件大小
 * @param int $size 大小值，以B为单位
 * @return string
 */
function format_filesize($size) {
    $sizename = array('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
    return $size ? round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $sizename[$i] : '0 Bytes';
}

/**
 * 获取秒数转换成天数后的值
 * @param int $seconds
 */
function get_day($seconds = 0) {
    return ceil($seconds / 86400);
}

/**
 * 获取客户端IP
 * @return string 获取的IP地址
 */
function get_ip() {
    if (!empty($_SERVER["HTTP_CLIENT_IP"]))
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    else if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
        $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
    else if (!empty($_SERVER["REMOTE_ADDR"]))
        $ip = $_SERVER["REMOTE_ADDR"];
    else
        $ip = '';
    preg_match("/[\d\.]{7,15}/", $ip, $ips);
    $ip = isset($ips[0]) ? $ips[0] : 'Unknown';
    unset($ips);
    return $ip;
}

/**
 * 地址跳转
 * @param string $url 跳转的地址
 */
function go($url = '/') {
    header("location:{$url}");
    exit;
}

/**
 * 获取顶级域名
 * @param string $url URL地址
 * @return string
 */
function get_domain($url) {
    if (!$url)
        return $url;
    $pattern = "/[\w-]+\.(com|net|org|gov|cc|biz|info|cn|co)(\.(cn|hk))*/";
    preg_match($pattern, $url, $matches);
    if (count($matches) > 0) {
        return $matches[0];
    } else {
        $rs = parse_url($url);
        $main_url = isset($rs['host']) ? $rs['host'] : $rs['path'];
        if (!strcmp((sprintf("%u", ip2long($main_url))), $main_url)) {
            return $main_url;
        } else {
            $arr = explode(".", $main_url);
            $count = count($arr);
            $endArr = array("com", "net", "org"); //com.cn  net.cn 等情况
            if (in_array($arr[$count - 2], $endArr)) {
                $domain = $arr[$count - 3] . "." . $arr[$count - 2] . "." . $arr[$count - 1];
            } else {
                $domain = $arr[$count - 2] . "." . $arr[$count - 1];
            }
            return $domain;
        }
    }
}

/**
 * 获取unixtime转换后的时间值
 * @param mixed $unixtime 数组或unixtime
 * @param bool $showtime 是否显示时间
 * @param bool $longtime 是否为13位时间
 * @return mixed 
 */
function get_datetime($unixtime = 0, $showtime = true, $longtime = false) {
    $is_array = is_array($unixtime);
    $unixtime = $is_array ? $unixtime : array($unixtime);
    foreach ($unixtime as $m => $n) {
        //$n = $n ? $n : time();
        $unixtime[$m] = date(($showtime ? 'Y-m-d H:i:s' : 'Y-m-d'), ($longtime ? $n / 1000 : $n));
    }
    return $is_array ? $unixtime : $unixtime[0];
}

/**
 * 获取纯数字字母mac地址,非原始(小写)
 * @param string $mac MAC地址
 * @return string
 */
function get_unoriginal_mac($mac = '') {
    return str_replace(':', '', strtolower($mac));
}

/**
 * 获取标准格式mac地址,原始(大写)
 * @param string $mac MAC地址
 * @return string
 */
function get_original_mac($mac = '') {
    return implode(':', str_split(strtoupper($mac), 2));
}

/**
 * 获取签名验证码
 * @return string
 */
function get_sig($params) {
    unset($params['sig']);
    ksort($params);

    $query_string = array();
    foreach ($params as $key => $val) {
        array_push($query_string, $key . '=' . (is_array($val) ? http_build_query($val) : $val));
    }
    $secret = strtoupper(rawurlencode(join('&', $query_string) . 'teamtop3'));
    $secret = str_replace(array('%2A', '%28', '%29', '%20'), array('*', '(', ')', '+'), $secret);
    return md5($secret);
}

/**
 * 获取当前脚本的URL地址
 * @return string
 */
function get_url() {
    if (!empty($_SERVER["REQUEST_URI"])) {
        $script_name = $_SERVER["REQUEST_URI"];
        $nowurl = $script_name;
    } else {
        $script_name = $_SERVER["PHP_SELF"];
        $nowurl = empty($_SERVER["QUERY_STRING"]) ? $script_name : $script_name . "?" . $_SERVER["QUERY_STRING"];
    }
    return $nowurl;
}

/**
 * 读取字符串中的数字
 * @param string $string
 * @return float
 */
function get_num($string) {
    preg_match("/[0-9]+(\.[0-9]{1,9})?/", $string, $result);
    return isset($result[0]) ? $result[0] : 0;
}

/**
 * 获取GET参数
 * @param string $param 参数名
 * @param string $default 默认
 * @return string
 */
function get_param($param, $default = '') {
    return isset($_GET[$param]) ? $_GET[$param] : $default;
}

/**
 * 获取浏览器
 * @param string $agent Agent头，默认为空
 * @return string 操作浏览器名称
 */
function get_bs($agent = '') {
    if (empty($agent))
        $agent = $_SERVER["HTTP_USER_AGENT"];
    if (strpos($agent, "Opera"))
        $bs = "Opera";
    else if (strpos($agent, "Firefox"))
        $bs = "Firefox";
    else if (strpos($agent, "Chrome"))
        $bs = "Chrome";
    else if (strpos($agent, "MSIE 6"))
        $bs = "IE6";
    else if (strpos($agent, "MSIE 7"))
        $bs = "IE7";
    else if (strpos($agent, "MSIE 8"))
        $bs = "IE8";
    else
        $bs = "Other";
    return $bs;
}

/**
 * 获取文件后缀
 * @param string $str 文件名
 * @return string
 */
function get_extension($str) {
    return strtolower(substr(strrchr($str, '.'), 1));
}

/**
 * 获取文本中的远程图片地址
 * @param string $str 文本内容
 * @return array
 */
function get_images($str) {
    preg_match_all('/<img(.*?)src=[\'\"]?([^\'\"]+)[\'\"]?/i', stripslashes($str), $matches, PREG_PATTERN_ORDER);
    $result = array();
    $images = $matches[2];
    foreach ($images as $value) {
        if (in_array(get_extension($value), array('gif', 'jpg', 'jpeg', 'png')))
            $result[] = $value;
    }
    return $result;
}

/**
 * 获取远程图片并下载
 * @param string $url 远程URL
 * @param string $dst_dir 本地存放目录
 * @param string $dst_filename 本地文件名，不带扩展名
 * @return string
 */
function get_http_image($url, $dst_dir, $dst_filename = false) {
    if (!empty($url)) {
        $fileurl = (!$dst_filename ? uniqid() : $dst_filename) . strrchr($url, ".");
        $filepath = dirname(BASEPATH) . $dst_dir;
        $filename = $filepath . $fileurl;
        if (!is_dir($filepath))
            @mk_dir($filepath);
        set_time_limit(0);
        $get_file = @file_get_contents($url);
        if ($get_file) {
            $fp = @fopen($filename, "w");
            @fwrite($fp, $get_file);
            @fclose($fp);
            return $dst_dir . $fileurl;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

/**
 * 将JSON转换成数组格式,只接收数组形式
 * @param mixed $data 需要处理的数据,例:get_json_array(array(&$aa, &$bb));
 * @return mixed
 */
function get_json_array($data) {
    if (is_array($data)) {
        foreach ($data as $m => $n) {
            $data[$m] = is_array($n) ? $n : obj2array(json_decode($n, true));
        }
    } else if ($data) {
        $data = obj2array(json_decode($data, true));
    } else {
        $data = array();
    }
    return $data;
}

/**
 * 将JSON转换成数组格式,只接收变量形式,例:get_json_var($aa);
 * @param array $data
 */
function get_json_var(& $data) {
    $data = get_json_array($data);
    return $data;
}

/**
 * 获取整型数据
 * @param mixed $data 需要处理的数据
 * @return mixed
 */
function get_int_type(& $data) {
    if (is_numeric($data) && !isset($data{13})) {
        $data = (float) $data;
    } else {
        if (is_array($data)) {
            foreach ($data as $m => $n) {
                //递归调用处理数据
                get_int_type($data[$m]);
            }
        }
    }
    return $data;
}

/**
 * 获得在线GOOGLE的翻译结果
 * @param string $text 翻译的文字
 * @param string $from 源语言，默认为zh-CN，可选zh-CN(中文),en(英文)
 * @param string $to 目标语言，默认为en，可选zh-CN(中文),en(英文)
 * @param string $replacespace 替换空格，默认为空格
 * @return string 翻译成功后的结果
 */
function google_translate($text, $from = 'zh-CN', $to = 'en', $replacespace = '-') {
    $text = preg_replace(array('/(\?|&|\/)/i'), '', $text);
    if (empty($text))
        return '';
    $content = @file_get_contents("http://translate.google.cn/translate_t?sl={$from}&tl={$to}&text=" . urlencode($text) . "#");
    if (!$content || empty($content))
        return false;
    preg_match_all("/<span\sid=result_box\sclass=\"short_text\">(.*?)<\/span>/si", $content, $matchs);
    $result = isset($matchs[0][0]) ? $matchs[0][0] : '';
    return str_replace(' ', $replacespace, strip_tags(iconv("GB2312", "UTF-8", trim($result))));
}

/**
 * HTML转文本简化,只替换style,frame,script,br
 * @param string $str 需要替换的字符
 * @return string
 */
function html2text($str) {
    $str = preg_replace("/<sty(.*)\\/style>|<scr(.*)\\/script>|<scr(.*)\\/script>|<!--(.*)-->/isU", '', $str);
    return strip_tags(str_replace(array('<br />', '<br>', '<br/>'), "\n", $str));
}

/**
 * XSS清除
 * @param string $str
 * @return string
 */
function xss_cleaner($str) {
    $result = str_replace(array("'", '"'), '', $str);
    $result = addslashes(trim($result));
    return $result;
}

/**
  Test if a timestamp matches a cron format or not
 */
function is_time_cron($time, $cron) {
    $cron_parts = explode(' ', $cron);
    if (count($cron_parts) != 5) {
        return false;
    }
    list($min, $hour, $day, $mon, $week) = explode(' ', $cron);
    $to_check = array('min' => 'i', 'hour' => 'G', 'day' => 'j', 'mon' => 'n', 'week' => 'w');
    $ranges = array(
        'min' => '0-59',
        'hour' => '0-23',
        'day' => '1-31',
        'mon' => '1-12',
        'week' => '0-6',
    );

    foreach ($to_check as $part => $c) {
        $val = $$part;
        $values = array();
        /*
          For patters like 0-23/2
         */
        if (strpos($val, '/') !== false) {
            //Get the range and step
            list($range, $steps) = explode('/', $val);
            //Now get the start and stop
            if ($range == '*') {
                $range = $ranges[$part];
            }
            list($start, $stop) = explode('-', $range);
            for ($i = $start; $i <= $stop; $i = $i + $steps) {
                $values[] = $i;
            }
        }
        /*
          For patters like :
          2
          2,5,8
          2-23
         */ else {
            $k = explode(',', $val);
            foreach ($k as $v) {
                if (strpos($v, '-') !== false) {
                    list($start, $stop) = explode('-', $v);

                    for ($i = $start; $i <= $stop; $i++) {
                        $values[] = $i;
                    }
                } else {
                    $values[] = $v;
                }
            }
        }
        if (!in_array(date($c, $time), $values) and (strval($val) != '*')) {
            return false;
        }
    }
    return true;
}

/**
 * 判断是否是AJAX请求
 * @return boolean
 */
function is_ajax() {
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
        return true;
    } else {
        return false;
    }
}

/**
 * 判断是否含有中文
 * @param string $str 判断字符
 */
function is_chinese($str) {
    preg_match('/[\x80-\xff]./', $str);
}

/**
 * 判断普通数据,只包含字母数字下划线
 * @param string $str 需要判断的字符
 * @return bool 成功返回true，失败返回false
 */
function is_normal($str) {
    return preg_match('/^[0-9a-z_]+$/i', trim($str));
}

/**
 * 判断Email地址
 * @param string $str 需要判断的Email地址
 * @return bool 成功返回true，失败返回false
 */
function is_email($str) {
    return preg_match("/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/", trim($str));
}

/**
 * 判断URL地址
 * @param string $str 需要判断的URL地址
 * @return bool 成功返回true，失败返回false
 */
function is_url($str) {
    return preg_match("/^http(s?):\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+(.+)*$/", $str);
}

/**
 * 判断是否提交于表单
 * @param string $method 请求的方法，默认为POST，可选GET
 * @return bool 成功返回true,失败返回false
 */
function is_submit($method = 'POST') {
    //判断方法是否相同，及顶级域名是否相同
    return ($_SERVER['REQUEST_METHOD'] == strtoupper($method) && get_domain((isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')) == get_domain($_SERVER['HTTP_HOST'])) ? true : false;
}

/**
 * 根据路径创建目录
 * @param string $dir 目录路径
 * @return bool 成功返回true
 */
function mk_dir($dir) {
    if (!file_exists($dir)) {
        mk_dir(dirname($dir));
        @mkdir($dir, 0777);
    } else {
        return true;
    }
}

/**
 * 生成随机字符
 * @param string $prefix 前缀
 * @param int $length 随机字符长度
 * @return string
 */
function num_rand($prefix = 'SG', $length = 10) {
    $list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    mt_srand((double) microtime() * 1000000);
    if ($length > 0) {
        while (strlen($prefix) < ($length + 2)) {
            $prefix .= $list[mt_rand(0, strlen($list) - 1)];
        }
    }
    return $prefix;
}

/**
 * 多级对象转数据
 * @param obj $object 待转换的对象
 * @return array
 */
function obj2array($object = NULL) {
    $array = (array) $object;
    foreach ($array as $key => $val) {
        //判断是否为对象或数组，因为数组中可能还会存在对象
        if (is_object($val) || is_array($val)) {
            $val = obj2array($val);
        }
        $array[$key] = $val;
    }
    return $array;
}

/**
 * POST 发送信息
 * @param string $url URL地址
 * @param mixed $params 参数
 * @return string 
 */
function post($url, $params = array()) {
    return request($url, $params, 'POST');
}

/**
 * GET 发送信息
 * @param string $url URL地址
 * @param mixed $params 参数
 * @return string 
 */
function get($url, $params = array()) {
    return request($url, $params, 'GET');
}

/**
 * CURL发送Request请求,含POST和REQUEST
 * @param string $url 请求的链接
 * @param mixed $params 传递的参数
 * @param string $method 请求的方法
 * @param mixed $options CURL的参数
 * @return array
 */
function request($url, $params = array(), $method = 'POST', $options = array()) {
    $method = strtoupper($method);
    $protocol = substr($url, 0, 5);
    $query_string = is_array($params) ? http_build_query($params) : $params;

    $ch = curl_init();
    $defaults = array();
    if ('GET' == $method) {
        $geturl = $query_string ? $url . (stripos($url, "?") !== false ? "&" : "?") . $query_string : $url;
        $defaults[CURLOPT_URL] = $geturl;
    } else {
        $defaults[CURLOPT_URL] = $url;
        $defaults[CURLOPT_POST] = 1;
        $defaults[CURLOPT_POSTFIELDS] = $query_string;
    }

    $defaults[CURLOPT_HEADER] = false;
    $defaults[CURLOPT_RETURNTRANSFER] = true;
    $defaults[CURLOPT_CONNECTTIMEOUT] = 3;

    // disable 100-continue
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));

    if ('https' == $protocol) {
        $defaults[CURLOPT_SSL_VERIFYPEER] = false;
        $defaults[CURLOPT_SSL_VERIFYHOST] = false;
    }

    curl_setopt_array($ch, (array) $options + $defaults);

    $ret = curl_exec($ch);
    $err = curl_error($ch);

    if (false === $ret || !empty($err)) {
        $errno = curl_errno($ch);
        $info = curl_getinfo($ch);
        curl_close($ch);
        return array(
            'result' => false,
            'errno' => $errno,
            'msg' => $err,
            'info' => $info,
        );
    }
    curl_close($ch);
    return array(
        'result' => true,
        'msg' => $ret,
    );
}

/**
 * 替换文本中的远程图片地址
 * @param string $str 文本内容
 * @param bool $water_mark 是否添加水印，默认为false
 * @return string
 */
function replace_remote_image($str, $water_mark = false) {
    @set_time_limit(0);
    $str = stripslashes($str);
    $imgs = get_images($str);
    if (!is_array($imgs))
        return $str;
    foreach ($imgs as $img) {
        $localimg[] = $img;
        if (substr($img, 0, 7) == 'http://') {
            $file = file_get_contents($img);
            if ($file) {
                $ext = get_extension($img);
                $filename = date('YmdHis') . rand(10000, 99999) . '.' . $ext;
                $name_path = UPLOADPATH . 'images/' . $filename;
                $fp = fopen($name_path, 'a');
                @fwrite($fp, $file);
                @fclose($fp);
                if ($water_mark) {
                    $framework = &get_instance('controller');
                    $framework->image->from($name_path);
                    $framework->image->watermark(DATAPATH . 'wm.png');
                    $framework->image->output($ext, $name_path);
                }
                $localimg[] = base_url() . 'uploads/' . $filename;
            }
        }
    }
    return addslashes(str_replace($imgs, $localimg, $str));
}

/**
 * 根据路径移除目录
 * @param string $dir 目录路径
 * @return bool 成功返回true，失败返回false
 */
function rm_dir($dir) {
    if (!is_dir($dir))
        return true;
    $dp = @opendir($dir);
    while (($name = @readdir($dp))) {
        if ($name != '.' && $name != '..') {
            $path = $dir . '/' . $name;
            if (!is_dir($path))
                @unlink($path);
            else
                @rm_dir($path);
        }
    }
    closedir($dp);
    return @rmdir($dir) ? true : false;
}

/**
 * 统计目录大小
 * @param string $dir 目录路径
 * @return int 目录大小
 */
function total_dir($dir) {
    $handle = @opendir($dir);
    $size = 0;
    while ($file = @readdir($handle)) {
        if ($file != '.' && $file != '..') {
            $path = $dir . '/' . $file;
            if (@is_dir($path))
                $size += total_dir($path);
            else
                $size += @ filesize($path);
        }
    }
    @closedir($handle);
    return $size;
}

/**
 * 替换文本中的URL
 * @param string $ret 需要替换的文本
 * @return string
 */
function replace_url($ret) {
    $ret = ' ' . $ret;
    $ret = preg_replace_callback('#([\s>])([\w]+?://[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]*)#is', 'replace_http_url', $ret);
    $ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]*)#is', 'replace_ftp_url', $ret);
    $ret = preg_replace_callback('#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', 'replace_email_url', $ret);
    //将已经存在的链接转换回来
    $ret = preg_replace("#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i", "$1$3</a>", $ret);
    $ret = trim($ret);
    return $ret;
}

function replace_http_url($matches) {
    $ret = '';
    $url = $matches[2];
    if (empty($url))
        return $matches[0];
    if (in_array(substr($url, -1), array('.', ',', ';', ':')) === true) {
        $ret = substr($url, -1);
        $url = substr($url, 0, strlen($url) - 1);
    }
    return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $ret;
}

function replace_ftp_url($matches) {
    $ret = '';
    $dest = $matches[2];
    $dest = 'http://' . $dest;
    if (empty($dest))
        return $matches[0];
    if (in_array(substr($dest, -1), array('.', ',', ';', ':')) === true) {
        $ret = substr($dest, -1);
        $dest = substr($dest, 0, strlen($dest) - 1);
    }
    return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>" . $ret;
}

function replace_email_url($matches) {
    $email = $matches[2] . '@' . $matches[3];
    return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
}

function curl_request_multi($connomains, $killspace = TRUE, $forhtml = TRUE, $timeout = 6, $header = 0, $follow = 1) {
    $res = array(); //用于保存结果 	    	
    //$connomains=array_flip(array_flip($connomains));//去除url中的重复项
    $mh = curl_multi_init(); //创建多curl对象，为了几乎同时执行		
    foreach ($connomains as $i => $url) {
        $conn[$url] = curl_init($url); //若url中含有gb2312汉字，例如FTP时，要在传入url的时候处理一下，这里不用
        curl_setopt($conn[$url], CURLOPT_TIMEOUT, $timeout); //此时间须根据页面的HTML源码出来的时间，一般是在1s内的，慢的话应该也不会6秒，极慢则是在16秒内
        curl_setopt($conn[$url], CURLOPT_HEADER, $header); //不返回请求头，只要源码
        curl_setopt($conn[$url], CURLOPT_RETURNTRANSFER, 1); //必须为1
        curl_setopt($conn[$url], CURLOPT_FOLLOWLOCATION, $follow); //如果页面含有自动跳转的代码如301或者302HTTP时，自动拿转向的页面
        curl_multi_add_handle($mh, $conn[$url]); //关键，一定要放在上面几句之下，将单curl对象赋给多对象
    }
    //下面一大步的目的是为了减少cpu的无谓负担，暂时不明，来自php.net的建议，几乎是固定用法
    do {
        $mrc = curl_multi_exec($mh, $active); //当无数据时或请求暂停时，active=true
    } while ($mrc == CURLM_CALL_MULTI_PERFORM); //当正在接受数据时
    while ($active and $mrc == CURLM_OK) {//当无数据时或请求暂停时，active=true,为了减少cpu的无谓负担,这一步很难明啊
        if (curl_multi_select($mh) != -1) {
            do {
                $mrc = curl_multi_exec($mh, $active);
            } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        }
    }
    //下面返回结果
    foreach ($connomains as $i => $url) {
        $cinfo = curl_getinfo($conn[$url]); //可用于取得一些有用的参数，可以认为是header
        //$url=$cinfo[url];//真实url,有些url
        if ($killspace) {//有点水消耗
            $str = trim(curl_multi_getcontent($conn[$url]));
            $str = preg_replace('/\s(?=\s)/', '', $str); //去掉跟随别的挤在一块的空白   	    
            $str = preg_replace('/[\n\r\t]/', ' ', $str);  //最后，去掉非space 的空白，用一个空格代替
            $res[$url] = stripslashes($str); //取得对象源码，并取消换行，节约内存的同时，可以方便作正则处理
        } else {
            $res[$url] = curl_multi_getcontent($conn[$url]);
        }
        if (!$forhtml) {//节约内存			
            $res[$url] = NULL;
        }
        curl_close($conn[$url]); //关闭所有对象 
        curl_multi_remove_handle($mh, $conn[$url]);   //用完马上释放资源           			   
    }
    curl_multi_close($mh);
    $mh = NULL;
    $conn = NULL;
    $connomains = NULL;
    return $res;
}

/**
 * 检测字符编码并转换
 * @param string $string 转换字符
 * @param string $out_encoding 转出数据
 * @return string 
 */
function safeencode($string, $out_encoding = 'UTF-8') {
    $in_encoding = mb_detect_encoding($string, 'UTF-8') === 'UTF-8' ? "UTF-8" : 'GBK';
    return strtoupper($in_encoding) == strtoupper($out_encoding) ? $string : @iconv($in_encoding, $out_encoding, $string);
}

/**
 * 获得数组元素的概率
 * @param array $ps array('p1'=>20, 'p2'=>30, 'p3'=>50);
 * @param array $num 默认为1,即随机出来的数量
 * @param array $uniqueunique 默认为true,即当num>1时,随机出的数量是否唯一
 * @return mixed 当num为1时返回键名,反之返回一维数组
 */
function random($ps, $num = 1, $unique = true) {
    if ($num > count($ps)) {
        return $num == 1 ? '' : array();
    }
    $max_exp = 0;
    $res = array();
    foreach ($ps as $key => $value) {
        $value = substr($value, 0, stripos($value, ".") + 6);
        $exp = strlen(strchr($value, '.')) - 1;
        if ($exp > $max_exp) {
            $max_exp = $exp;
        }
    }
    $pow_exp = pow(10, $max_exp);
    if ($pow_exp > 1) {
        reset($ps);
        foreach ($ps as $key => $value) {
            $ps[$key] = $value * $pow_exp;
        }
    }
    $pro_sum = array_sum($ps);
    if ($pro_sum < 1) {
        return $num == 1 ? '' : array();
    }
    for ($i = 0; $i < $num; $i++) {
        $rand_num = mt_rand(1, $pro_sum);
        reset($ps);
        foreach ($ps as $key => $value) {
            if ($rand_num <= $value) {
                break;
            } else {
                $rand_num -= $value;
            }
        }
        if ($num == 1) {
            $res = $key;
            break;
        } else {
            $res[$i] = $key;
        }
        if ($unique) {
            $pro_sum -= $value;
            unset($ps[$key]);
        }
    }
    return $res;
}

/**
 * 判断$needle中是否含有$haystack中的一个元素
 * @param array $haystack 查找的字符数组
 * @param string $needle 判断的字符串
 * @return boolean 成功返回存在的字符
 */
function strstr_array($haystack, $needle) {
    if (!is_array($haystack)) {
        return false;
    }
    foreach ($haystack as $element) {
        if (stristr($needle, $element)) {
            return $element;
        }
    }
    return false;
}

/**
 * 计算从开始到最后使用的时间
 * @return float
 */
function used_microtime() {
    return round(microtime(true) - START_TIME, 7);
}

/**
 * 设置一个时间调试断点
 * @param string $tag 断点标识符,默认使用default,后面使用get_break()进行获取执行时间
 * @return float
 */
function set_break($tag = 'default') {
    $GLOBALS['point'][$tag] = microtime(true);
    return $GLOBALS['point'][$tag];
}

/**
 * 计算从一个指定断点标识符到现在的运行时间
 * @staticvar var $point  时间调试内部静态变量
 * @param string $tag 断点标识符,默认使用default,可在此之前使用set_break()进行设置时间断点调试
 * @return float
 */
function get_break($tag = 'default') {
    global $point;
    $now = microtime(true);
    return (isset($point[$tag]) && is_numeric($point[$tag])) ? round($now - $point[$tag], 7) :
            ((isset($point['default']) && is_numeric($point['default'])) ? round($now - $point['default'], 7) : used_microtime());
}

/**
 * 获取程序消耗的内存量
 * @return string 以KB计算的内存消耗值
 */
function used_memeory() {
    return round((memory_get_usage() / 1024) - START_MEMORY_USAGE / 1024, 2) . ' KB';
}

/**
 * 获取一个基于时间的Unix时间戳
 * @param string $type 时间类型，默认为day，可选minute,hour,day,week,month,quarter,year
 * @param int $offset 时间偏移量 默认为0，正数表示当前type之后，负数表示当前type之前
 * @param string $position 时间的开始或结束，默认为begin，可选前(begin,start,first,front)，end
 * @param int $year 基准年，默认为null，即以当前年为基准
 * @param int $month 基准月，默认为null，即以当前月为基准
 * @param int $day 基准天，默认为null，即以当前天为基准
 * @param int $hour 基准小时，默认为null，即以当前年小时基准
 * @param int $minute 基准分钟，默认为null，即以当前分钟为基准
 * @return int 处理后的Unix时间戳
 */
function get_unixtime($type = 'day', $offset = 0, $position = 'begin', $year = null, $month = null, $day = null, $hour = null, $minute = null) {
    $year = is_null($year) ? date('Y') : $year;
    $month = is_null($month) ? date('m') : $month;
    $day = is_null($day) ? date('d') : $day;
    $hour = is_null($hour) ? date('H') : $hour;
    $minute = is_null($minute) ? date('i') : $minute;
    $position = in_array($position, array('begin', 'start', 'first', 'front'));

    switch ($type) {
        case 'minute':
            return $position ? mktime($hour, $minute + $offset, 0, $month, $day, $year) : mktime($hour, $minute + $offset, 59, $month, $day, $year);
            break;
        case 'hour':
            return $position ? mktime($hour + $offset, 0, 0, $month, $day, $year) : mktime($hour + $offset, 59, 59, $month, $day, $year);
            break;
        case 'day':
            return $position ? mktime(0, 0, 0, $month, $day + $offset, $year) : mktime(23, 59, 59, $month, $day + $offset, $year);
            break;
        case 'week':
            return $position ? mktime(0, 0, 0, $month, $day - date("w", mktime(0, 0, 0, $month, $day, $year)) + 1 - 7 * (-$offset), $year) : mktime(23, 59, 59, $month, $day - date("w", mktime(0, 0, 0, $month, $day, $year)) + 7 - 7 * (-$offset), $year);
            break;
        case 'month':
            return $position ? mktime(0, 0, 0, $month + $offset, 1, $year) : mktime(23, 59, 59, $month + $offset, get_month_days($month + $offset, $year), $year);
            break;
        case 'quarter':
            return $position ? mktime(0, 0, 0, 1 + ((ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) - 1) * 3, 1, $year) : mktime(23, 59, 59, (ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) * 3, get_month_days((ceil(date('n', mktime(0, 0, 0, $month, $day, $year)) / 3) + $offset) * 3, $year), $year);
            break;
        case 'year':
            return $position ? mktime(0, 0, 0, 1, 1, $year + $offset) : mktime(23, 59, 59, 12, 31, $year + $offset);
            break;
        default:
            return mktime($hour, $minute, 0, $month, $day, $year);
            break;
    }
}

/**
 * 获取月的天数
 * @param int $month 月份，默认为null，即计算当前月的天数
 * @param int $year 年份，默认为null，即基于当前年
 * @return int
 */
function get_month_days($month = null, $year = null) {
    //也可以使用return cal_days_in_month(CAL_GREGORIAN, $month, $year);
    $year = is_null($year) ? date('Y') : $year;
    $month = is_null($month) ? date('m') : $month;
    return date("t", mktime(0, 0, 0, $month, 1, $year));
}

/**
 * 格式化时间为相对人类时间
 * @param int $date UNIX时间格式的值
 * @param bool $showdate 当未获取到指定人类时间时，是否显示普通时间，默认为true
 * @return string 处理后的人类时间
 */
function format_time($date, $showdate = true) {
    if (!is_numeric($date))
        return date("Y-m-d");
    $limit = time() - $date;
    if ($limit < 0)
        return '来自古代';
    else if ($limit == 0)
        return '刚刚';
    else if ($limit < 60)
        return $limit . '秒钟前';
    else if ($limit >= 60 && $limit < 3600)
        return floor($limit / 60) . '分钟前';
    else if ($limit >= 3600 && $limit < 86400)
        return floor($limit / 3600) . '小时前';
    else if ($limit >= 86400 && $limit < 604800)
        return floor($limit / 86400) . '天前';
    else if ($limit >= 604800 && $limit < 2592000)
        return floor($limit / 604800) . '周前';
    else if ($limit >= 2592000 && $limit < 31536000)
        return floor($limit / 2592000) . '个月前';
    else if ($limit >= 31536000 && $limit < 315360000)
        return floor($limit / 31536000) . '年前';
    else
        return ($limit >= 315360000 && $showdate) ? date('Y-m-d H:i:s', $date) : '';
}

/**
 * 调试记录信息,支持数组和字符串,不支持对象
 */
function debug() {
    $arg_list = func_get_args();
    $arg_nums = func_num_args();
    $temp = array();
    for ($i = 0; $i < $arg_nums; $i++) {
        $temp[] = is_array($arg_list[$i]) ? array2val($arg_list[$i]) : $arg_list[$i];
    }
    log_message("debug:<font color=purple>" . implode('</font>,<font color=purple>', $temp) . '</font>', 'error');
}

/**
 * 控制台打印输出
 * @param mixed $data
 * @return boolean 
 */
function r($data) {
    Chrome::log($data);
    return false;
    echo "<xmp>";
    print_r($data);
    echo "</xmp>";
}

function curl_multi_post($url, $fields = array()) {
    $master = curl_multi_init();
    $node_count = count($fields);
    $curl_arr = array();
    for ($i = 0; $i < $node_count; $i++) {
        $params = $fields[$i];
        //批量初始化curl资源
        $curl_arr[$i] = curl_init($url);
        //设置curl参数
        curl_setopt($curl_arr[$i], CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl_arr[$i], CURLOPT_POSTFIELDS, $params);
        //批量增加句柄
        curl_multi_add_handle($master, $curl_arr[$i]);
    }

    $running = null;
    do {
        //执行
        curl_multi_exec($master, $running);
    } while ($running > 0);

    for ($i = 0; $i < $node_count; $i++) {
        $results[$i] = curl_multi_getcontent($curl_arr[$i]);
        //释放句柄
        curl_multi_remove_handle($master, $curl_arr[$i]);
    }
    //务必要关闭资源
    curl_multi_close($master);
    return $results;
}